package com.yicong.ants.manager.http;

import android.app.Activity;
import android.os.Build;
import android.os.Environment;

import com.aliyun.TigerTally.TigerTallyAPI;
import com.blankj.utilcode.util.GsonUtils;
import com.cchao.simplelib.Const;
import com.cchao.simplelib.LibCore;
import com.cchao.simplelib.core.JsonHelper;
import com.cchao.simplelib.core.Logs;
import com.cchao.simplelib.core.RxBus;
import com.cchao.simplelib.core.RxHelper;
import com.cchao.simplelib.core.UiHelper;
import com.cchao.simplelib.http.OkHttpHelper;
import com.cchao.simplelib.http.SslCertHelper;
import com.cchao.simplelib.http.callback.StringCallBack;
import com.cchao.simplelib.util.UrlUtil;
import com.cchao.simplelib.util.UuidUtil;
import com.geetest.captcha.GTCaptcha4Client;
import com.geetest.captcha.GTCaptcha4Config;
import com.google.gson.JsonObject;
import com.yicong.ants.App;
import com.yicong.ants.BuildConfig;
import com.yicong.ants.Constants;
import com.yicong.ants.Cx;
import com.yicong.ants.R;
import com.yicong.ants.bean.account.UserBean;
import com.yicong.ants.bean.base.RespBean;
import com.yicong.ants.manager.AppHelper;
import com.yicong.ants.manager.BusinessHelper;
import com.yicong.ants.manager.UserManager;
import com.yicong.ants.manager.business.SignHelper;
import com.yicong.ants.utils.AmapHelper;
import com.yicong.ants.utils.ToastUtils;
import com.zx.sdk.ZxSDK;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;

import io.reactivex.disposables.Disposable;
import kotlin.text.Charsets;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;

/**
 * 网络请求管理类
 */
public class OkHttpManager {

    //需要和服务端保持一致
    public static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/x-www-form-urlencoded; charset=utf-8");
    private static final String TAG = OkHttpManager.class.getSimpleName();
    //下面两个随便用哪个都可以
    //    private static final MediaType MEDIA_TYPE_FILE = MediaType.parse("application/octet-stream");
    private static final MediaType MEDIA_TYPE_FILE = MediaType.parse("image/jpg");
    // 后端api 的分页 处理
    static Pattern mPattern = Pattern.compile("\"pageInfo\":\\{(.*?)\\},\"(\\w+?)\":\\[");
    // 分页处理 白名单
    static String[] mWhiteListPageResp = {"/api/v1/senic/allsenic"};

    public static Map<String, String> getCommonParams() {
        Map<String, String> commonParams = new HashMap<>();
        commonParams.put("platform", "2");
        commonParams.put("source", "ant");
        // 直播需要
        commonParams.put("appcode", "ant");
        commonParams.put("appVersion", String.valueOf(BuildConfig.VERSION_CODE));
        commonParams.put("app_id", String.valueOf(LibCore.getInfo().getAppId()));
        commonParams.put("uuid", UuidUtil.getUniqueID(LibCore.getContext()));
        if (UserManager.isLogin()) {
            commonParams.put("token", UserManager.getUserBean().getJwt_token());
        }
        return commonParams;
    }

    public static OkHttpClient getHttpClient() {
        return OkHttpHelper.getClient();
    }

    public static OkHttpClient getOriginClient() {
        OkHttpClient.Builder clientBuilder = OkHttpHelper.getDefault().newBuilder()
                .addInterceptor(OkHttpManager::getNetInterceptor)
                .addInterceptor(chain -> {
                    //region  修改响应的列表字段，成 list
                    Request request = chain.request();
                    Response response = chain.proceed(request);
                    // 正常响应
                    if (response.isSuccessful()) {
                        for (String api : mWhiteListPageResp) {
                            // 白名单不做处理
                            if (request.url().url().getPath().contains(api)) {
//                            return response;
                            }
                        }
                        BufferedSource source = response.body().source();
                        source.request(Long.MAX_VALUE);
                        Buffer buffer = source.buffer();

                        // 复制一份响应
                        String json = buffer.clone().readString(Const.CHARSET_UTF_8).trim();

                        try {
                            RespBean bean = JsonHelper.toObject(json, RespBean.class);
                            if (bean != null) {
                                switch (bean.code) {
                                    case "3000":
                                        UserManager.logout();
                                        RxBus.get().postEvent(Constants.Event.Login_Out);
                                        break;
                                    case "1012":
                                    case "4000":
                                        RxBus.get().postEvent(Constants.Event.To_Auth, bean.msg);
                                        break;
                                    case "4010":
                                        RxBus.get().postEvent(Constants.Event.Bio_Auth, bean.msg);
                                        break;
                                    case "4050":
                                        Object data = bean.getData();
                                        if (!(data instanceof Map)) break;
                                        Activity topActivity = App.mLifecycleCallListener.mTopActivity;
                                        topActivity.runOnUiThread(() -> {
                                            try {
                                                String errorMsg = "验证失败，请重试！";
                                                GTCaptcha4Client[] gtCaptcha4Client = new GTCaptcha4Client[1];
                                                gtCaptcha4Client[0] = GTCaptcha4Client.getClient(topActivity)
                                                        .init(((Map<?, ?>) data).get("captcha_id") + "", new GTCaptcha4Config.Builder()
                                                                .setDebug(false)
                                                                .setLanguage("zh")
                                                                .setTimeOut(10000)
                                                                .setCanceledOnTouchOutside(true)
                                                                .build())
                                                        .addOnSuccessListener((status, response1) -> {
                                                            if (status) {
                                                                Map<String, String> params = JsonHelper.toMap(response1, String.class);
                                                                params.put("type", ((Map<?, ?>) data).get("type") + "");
                                                                params.put("mobile", ((Map<?, ?>) data).get("mobile") + "");
                                                                Disposable subscribe = RetrofitHelper.getApis().check(params)
                                                                        .compose(RxHelper.toMain())
                                                                        .subscribe(respBean -> {
                                                                            if (respBean.isCodeFail()) {
                                                                                UiHelper.showLongToast(respBean.getMsg());
                                                                                return;
                                                                            }
                                                                            RxBus.get().postEvent(Constants.Event.Real_Check_Suc);
                                                                        }, RxHelper.getErrorConsumer());
                                                            } else {
                                                                ToastUtils.showLong(topActivity, errorMsg);
                                                            }
                                                            gtCaptcha4Client[0].destroy();
                                                        })
                                                        .addOnFailureListener(error -> {
                                                            ToastUtils.showLong(topActivity, errorMsg);
                                                            gtCaptcha4Client[0].destroy();
                                                        })
                                                        .verifyWithCaptcha();
                                            } catch (Exception e) {
                                                Logs.logException(e);
                                            }
                                        });
                                        break;
                                }
                            }
                        } catch (Exception ex) {
                        }

                        // 正则替换
                        json = mPattern.matcher(json).replaceFirst("\"pageInfo\":{$1},\"list\":[");
                        ResponseBody body = ResponseBody.create(response.body().contentType(), json);
                        return response.newBuilder().body(body).build();
                    }
                    return response;
                    //endregion
                });

        if (AppHelper.isDebug() || AppHelper.isTestEnv()) {
            SslCertHelper.enableTrustAllCert(clientBuilder);
        }

        return clientBuilder.build();
    }

    /**
     * 网关拦截器
     */
    private static Response getNetInterceptor(okhttp3.Interceptor.Chain chain) throws IOException {
        Request request = chain.request();
        Request.Builder builder = request.newBuilder();
        TreeMap<String, String> hintHeads = new TreeMap<>(getCommonParams());
        TreeMap<String, String> map = new TreeMap<>();

        String nonceStr = BusinessHelper.generatingRandomString();
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        hintHeads.put(Constants.Keys.noncestr, nonceStr);
        hintHeads.put(Constants.Keys.timestamp, timestamp);
        for (Map.Entry<String, String> entry : hintHeads.entrySet()) {
            builder.addHeader(entry.getKey(), entry.getValue());
        }

        // 有定位信息
        if (AmapHelper.mAMapLocation != null) {
            map.put("latitude", String.valueOf(AmapHelper.mAMapLocation.getLatitude()));
            map.put("longitude", String.valueOf(AmapHelper.mAMapLocation.getLongitude()));
            map.put("ad-code", String.valueOf(AmapHelper.mAMapLocation.getAdCode()));
        }
        map.put("appVersion", String.valueOf(BuildConfig.VERSION_CODE));

        // 已登录
        if (UserManager.isLogin()) {
            UserBean userBean = UserManager.getUserBean();
            map.put("uid", userBean.getId());
            map.put("mobile", userBean.getMobile());

            // 追加签名
            if (request.url().url().toString().contains("/task/onAdVideo")) {
                builder.addHeader(UiHelper.getString(R.string.ss2), Cx.pwdMD5(UserManager.getUserId() + timestamp));
            }
        }

        RequestBody body = request.body();
        boolean isPost = (body != null && body instanceof FormBody);
        // 追加上层传参
        if (isPost) {
            FormBody formBody = (FormBody) body;
            for (int i = 0; i < formBody.size(); i++) {
                map.put(formBody.name(i), formBody.value(i));
            }
        }
        TreeMap<String, String> signMap = new TreeMap<>(map);
        // 放入get请求参数,参与签名
        if (!request.url().queryParameterNames().isEmpty()) {
            for (String name : request.url().queryParameterNames()) {
                for (String value : request.url().queryParameterValues(name)) {
                    signMap.put(name, value);
                }
            }
        }

        // protect proguard
        if (System.currentTimeMillis() < 90000) {
            FileOutputStream outputStream = null;
            try {
                File filesDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + LibCore.getContext().getPackageName());
                File file = new File(filesDir, "mx2.t");
                outputStream = new FileOutputStream(file);
                outputStream.write("x1".getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.flush();
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        String signature = "";
        try {
            if (chain.request().url().url().toString().contains(ZxSDK.BASE_API_URL)) {
                final Buffer buffer2 = new Buffer();
                request.body().writeTo(buffer2);
                String json = buffer2.readString(Charsets.UTF_8);
                JsonObject jsonObject = GsonUtils.fromJson(json, JsonObject.class);
                Set<String> entrySet = jsonObject.keySet();
                signMap.clear();
                for (String key : entrySet) {
                    signMap.put(key, jsonObject.get(key).getAsString());
                }
                signature = SignHelper.x2(signMap, nonceStr, timestamp);
            } else {
                signature = SignHelper.x(signMap, nonceStr, timestamp);
            }
        } catch (Exception e) {
            signature = SignHelper.x(signMap, nonceStr, timestamp);
        }
        map.put(UiHelper.getString(R.string.sign), signature);
        builder.addHeader(UiHelper.getString(R.string.sign), signature);
        if (isPost) {
            request = builder.post(getFormBody(map)).build();
        } else {
            String url = UrlUtil.buildUrl(request.url().url().toString(), map);
            request = builder.url(url).build();
        }
        try {
            String bodyContent = "";
            if (request.body() != null) {
                Buffer buffer = new Buffer();
                request.body().writeTo(buffer);
                bodyContent = buffer.readString(Charsets.UTF_8);
            }
            String wToken = TigerTallyAPI.vmpSign(1, bodyContent.getBytes(StandardCharsets.UTF_8));
            request = builder.addHeader("wToken", wToken).build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return chain.proceed(request);
    }

    public static FormBody getFormBody(Map<String, String> map) {
        return getFormBodyBuilder(map).build();
    }

    public static FormBody.Builder getFormBodyBuilder(Map<String, String> map) {

        FormBody.Builder builder = new FormBody.Builder();
        String params = "";
        for (Map.Entry<String, String> entry : map.entrySet()) {
            builder.add(entry.getKey(), entry.getValue() + "");
            params += entry.getKey() + ":" + entry.getValue() + "\\n";
        }

        Logs.e("请求 params :" + params);
        return builder;
    }

    /**
     * post异步请求
     *
     * @param url       接口地址
     * @param paramsMap 请求参数
     * @param callBack  请求返回数据回调
     * @return
     */
    public static void postByAsyn(String url, Map<String, Object> paramsMap, final OkHttpCallback callBack) {
        StringBuilder tempParams = new StringBuilder();
        int pos = 0;
        for (String key : paramsMap.keySet()) {
            if (pos > 0) {
                tempParams.append("&");
            }
            if (paramsMap.get(key) == null) {
                continue;
            }
            try {
                tempParams.append(String.format("%s=%s", key, URLEncoder.encode(paramsMap.get(key).toString(), "utf-8")));
            } catch (UnsupportedEncodingException e) {
                Logs.logException(e);
            }
            pos++;
        }
        String params = tempParams.toString();
        RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, params);

        OkHttpHelper.post(url, body, new StringCallBack() {
            @Override
            public void onRespond(Call call, String respStr) throws Exception {
                onSuccessCallBack(call, respStr, callBack);
            }

            @Override
            public void onError(Call call, Exception e) {
                super.onError(call, e);
                Logs.logException("网络异常" + call.request().url().url() + e.getMessage());
                onFailCallBack(e, callBack);
            }
        });
    }

    /**
     * 上传图片
     *
     * @param actionUrl
     * @param paramsMap
     * @param fileMap
     * @param callBack
     */
    public static void postFiles(String actionUrl, Map<String, Object> paramsMap, Map<String, File> fileMap, final OkHttpCallback callBack) {
        MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);

        //入参-字符串
        for (Map.Entry entry : paramsMap.entrySet()) {
            requestBody.addFormDataPart(entry.getKey().toString(), entry.getValue().toString());
        }
        //入参-文件
        for (Map.Entry entry : fileMap.entrySet()) {
            File file = (File) entry.getValue();
            RequestBody fileBody = RequestBody.create(MEDIA_TYPE_FILE, file);
            String fileName = file.getName();
            requestBody.addFormDataPart(entry.getKey().toString(), fileName, fileBody);
        }

        Request request = addHeaders().url(actionUrl).post(requestBody.build()).build();
        getHttpClient().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Logs.logException("网络异常" + call.request().url().url() + e.getMessage());
                onFailCallBack(e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    onFailCallBack(new IOException("响应出错"), callBack);
                }
                try {
                    String content = response.body().string();
                    onSuccessCallBack(call, content, callBack);
                } catch (Exception e) {
                    e.printStackTrace();
                    Logs.logException(e);
                }
            }
        });
    }

    private static void onSuccessCallBack(Call call, String content, OkHttpCallback callBack) {
        UiHelper.runOnUiThread(() -> {
            if (callBack != null) {
                callBack.onSuccess(call, content);
            }
        });
    }

    private static void onFailCallBack(Exception e, OkHttpCallback callBack) {
        UiHelper.runOnUiThread(() -> {
            if (callBack != null) {
                callBack.onFailure(e);
            }
        });
    }

    /**
     * 添加请求头
     *
     * @return
     */
    private static Request.Builder addHeaders() {
        Request.Builder builder = new Request.Builder()
                //addHeader，可添加多个请求头  header，唯一，会覆盖
                .addHeader("Connection", "keep-alive")
                .addHeader("platform", "2")
                .addHeader("phoneModel", Build.MODEL)
                .addHeader("systemVersion", Build.VERSION.RELEASE)
                .addHeader("appVersion", "3.2.0")
                .header("sid", "eyJhZGRDaGFubmVsIjoiYXBwIiwiYWRkUHJvZHVjdCI6InFia3BsdXMiLCJhZGRUaW1lIjoxNTAzOTk1NDQxOTEzLCJyb2xlIjoiUk9MRV9VU0VSIiwidXBkYXRlVGltZSI6MTUwMzk5NTQ0MTkxMywidXNlcklkIjoxNjQxMTQ3fQ==.b0e5fd6266ab475919ee810a82028c0ddce3f5a0e1faf5b5e423fb2aaf05ffbf");
        return builder;
    }

    public static String getReqParam(Request request, String key) {
        boolean isPost = (request.body() != null && request.body() instanceof FormBody);
        // 追加上层传参
        if (isPost) {
            FormBody formBody = (FormBody) request.body();
            for (int i = 0; i < formBody.size(); i++) {
                if (formBody.name(i).equalsIgnoreCase(key)) {
                    return formBody.value(i);
                }
            }
        } else {
            if (!request.url().queryParameterNames().isEmpty()) {
                for (String name : request.url().queryParameterNames()) {
                    if (name.equalsIgnoreCase(key)) {
                        return request.url().queryParameterValues(name).get(0);
                    }
                }
            }
        }
        return "";
    }

    /**
     * 请求回调
     */
    public interface OkHttpCallback {
        /**
         * 响应成功
         */
        void onSuccess(Call call, String content);


        /**
         * 响应失败
         */
        void onFailure(Exception e);
    }

}
